package com.googlecode.javarpctp.test.client;

import com.googlecode.javarpctp.client.Client;
import com.googlecode.javarpctp.client.ClientConnectionListener;
import com.googlecode.javarpctp.client.ClientException;
import com.googlecode.javarpctp.client.DisconnectionCause;
import com.googlecode.javarpctp.test.common.LoggedEvent;
import com.googlecode.javarpctp.test.common.ThreadCreatedEvent;
import com.googlecode.javarpctp.test.common.ThreadStateChangedEvent;
import com.googlecode.javarpctp.communication.ConnectionHandlerMessageTransportEvent;
import com.googlecode.javarpctp.test.shared.FooService;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import com.googlecode.javarpctp.test.common.LoggedListener;
import com.googlecode.javarpctp.test.common.Logger;
import com.googlecode.javarpctp.test.common.ThreadListener;
import com.googlecode.javarpctp.test.common.ThreadMonitor;
import com.googlecode.javarpctp.test.common.ThreadMonitorListener;
import com.googlecode.javarpctp.communication.ConnectionHandlerMessageTransportListener;
import java.util.ArrayList;
import java.util.EventObject;
import javax.swing.JDialog;

/**
 *
 * @author ConradoQG
 */
public class Main extends javax.swing.JFrame {

    private Client client;
    private ThreadMonitor threadMonitor = new ThreadMonitor();

    /** Creates new form Main */
    public Main() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException e) {
            // handle exception
        } catch (ClassNotFoundException e) {
            // handle exception
        } catch (InstantiationException e) {
            // handle exception
        } catch (IllegalAccessException e) {
            // handle exception
        }

        initComponents();

        this.setLocationRelativeTo(null);

        this.client = new Client("localhost", 5000);

        this.client.addClientConnectionListener(new ClientConnectionListener() {

            @Override
            public void connected(EventObject evt) {
                jConnect.setEnabled(false);
                jSendMessage.setEnabled(true);
                jDisconnect.setEnabled(true);
            }

            @Override
            public void disconnected(EventObject evt) {
                Client source = (Client) evt.getSource();
                jConnect.setEnabled(true);
                jSendMessage.setEnabled(false);
                jDisconnect.setEnabled(false);
                if (source.getDisconnectionCause() == DisconnectionCause.EXCEPTION) {
                    JOptionPane.showMessageDialog(
                            Main.this, 
                            "Server has been disconnected by exception " + source.getDisconnectionException().getMessage(), 
                            "Attention", 
                            JOptionPane.ERROR_MESSAGE);
                }
                /*
                if (((Client)evt.getSource()).getConnectionHandler().getStopCause() == ConnectionHandler.StopCause.EXCEPTION)
                    Logger.getInstance().log(Level.SEVERE, "Error", ((Client)evt.getSource()).getConnectionHandler().getStopException());
                 * */                 
            }
        });
        this.client.addThreadListener(new ThreadListener() {

            @Override
            public void threadCreated(ThreadCreatedEvent evt) {
                threadMonitor.addThreadToMonitor(evt.getThread());
            }
        });
        this.client.addConnectionHandlerMessageTransportListener(new ConnectionHandlerMessageTransportListener() {

            @Override
            public void messageTransported(final ConnectionHandlerMessageTransportEvent evt) {
                java.awt.EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        addMessageToHistory(evt);
                    }
                });
            }
        });
        threadMonitor.addThreadMonitorListener(new ThreadMonitorListener() {

            @Override
            public void threadStateChanged(final ThreadStateChangedEvent evt) {
                java.awt.EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        updateOrAddThread(evt.getThread());
                    }
                });
            }
        });
        threadMonitor.start();

        Logger.getInstance().addLoggedListener(new LoggedListener() {

            @Override
            public void logged(LoggedEvent evt) {
                final String finalMessage = evt.getMessage();
                final Level finalLevel = evt.getLevel();
                final Throwable finalThrown = evt.getThrown();

                java.awt.EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        if (finalThrown != null) {
                            jConsole.append(finalThrown.getMessage());
                            if (finalThrown.getCause() != null) {
                                jConsole.append(": " + finalThrown.getCause().getMessage());
                            }
                            jConsole.append("\n");
                        } else {
                            jConsole.append(finalMessage + "\n");
                        }
                        java.util.logging.Logger.getLogger(Main.class.getName()).log(finalLevel, finalMessage, finalThrown);
                    }
                });
            }
        });
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jButtonPanel = new javax.swing.JPanel();
        jConnect = new javax.swing.JButton();
        jSendMessage = new javax.swing.JButton();
        jDisconnect = new javax.swing.JButton();
        jSplitPane = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        jConsole = new javax.swing.JTextArea();
        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        jThreads = new javax.swing.JTable();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        jMessages = new javax.swing.JTable();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Client");
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jButtonPanel.setLayout(new javax.swing.BoxLayout(jButtonPanel, javax.swing.BoxLayout.Y_AXIS));

        jConnect.setText("Connect");
        jConnect.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jConnect.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jConnectActionPerformed(evt);
            }
        });
        jButtonPanel.add(jConnect);

        jSendMessage.setText("SendMessage");
        jSendMessage.setEnabled(false);
        jSendMessage.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jSendMessageActionPerformed(evt);
            }
        });
        jButtonPanel.add(jSendMessage);

        jDisconnect.setText("Disconnect");
        jDisconnect.setEnabled(false);
        jDisconnect.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jDisconnectActionPerformed(evt);
            }
        });
        jButtonPanel.add(jDisconnect);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.gridheight = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
        getContentPane().add(jButtonPanel, gridBagConstraints);

        jSplitPane.setDividerLocation(150);
        jSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        jScrollPane1.setViewportBorder(javax.swing.BorderFactory.createTitledBorder("Console"));

        jConsole.setBackground(new java.awt.Color(0, 0, 0));
        jConsole.setColumns(20);
        jConsole.setEditable(false);
        jConsole.setForeground(new java.awt.Color(255, 255, 255));
        jConsole.setRows(5);
        jScrollPane1.setViewportView(jConsole);

        jSplitPane.setLeftComponent(jScrollPane1);

        jSplitPane1.setDividerLocation(135);
        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane1.setPreferredSize(new java.awt.Dimension(454, 300));

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Threads"));
        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.LINE_AXIS));

        jThreads.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "ID", "Name", "State"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.Long.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane2.setViewportView(jThreads);

        jPanel1.add(jScrollPane2);

        jSplitPane1.setLeftComponent(jPanel1);

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Messages transported"));
        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.LINE_AXIS));

        jMessages.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Class type", "Direction", "Data"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, false, false
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane3.setViewportView(jMessages);

        jPanel2.add(jScrollPane3);

        jSplitPane1.setRightComponent(jPanel2);

        jSplitPane.setRightComponent(jSplitPane1);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        getContentPane().add(jSplitPane, gridBagConstraints);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jConnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jConnectActionPerformed
        try {
            this.client.connect();
        } catch (ClientException ex) {
            Logger.getInstance().log(Level.SEVERE, null, ex);
            JOptionPane.showMessageDialog(this, ex.getMessage(), "Connection problem", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_jConnectActionPerformed

    private void jDisconnectActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jDisconnectActionPerformed
        try {
            this.client.disconnect();
        } catch (ClientException ex) {
            Logger.getInstance().log(Level.SEVERE, null, ex);
            JOptionPane.showMessageDialog(this, ex.getMessage(), "Disconnection problem", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_jDisconnectActionPerformed

    private void jSendMessageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSendMessageActionPerformed
        
        FooService service = this.client.getServerCallService(FooService.class);
        
        System.out.println(service.bar(15));
        try {
            System.out.println(service.thrown());
        } catch (Exception ex) {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        service = this.client.getServerExecuteService(FooService.class);
        System.out.println(service.bar(15));

    }//GEN-LAST:event_jSendMessageActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Main().setVisible(true);
            }
        });
    }

    private void addMessageToHistory(ConnectionHandlerMessageTransportEvent evt) {
        ((DefaultTableModel) this.jMessages.getModel()).addRow(new String[]{evt.getMessage().getClass().getSimpleName(), evt.getMessageDirection().name(), evt.getMessage().toString()});
        this.jMessages.repaint();
    }

    private void updateOrAddThread(Thread thread) {
        int rowCount = ((DefaultTableModel) this.jThreads.getModel()).getRowCount();
        boolean threadFound = false;
        ArrayList<Integer> rowsToRemove = new ArrayList<Integer>();
        for (int i = 0; i < rowCount; i++) {
            Long threadID = (Long) ((DefaultTableModel) this.jThreads.getModel()).getValueAt(i, 0);
            if (threadID.equals(thread.getId())) {
                threadFound = true;
                if (thread.getState() == Thread.State.TERMINATED) {
                    rowsToRemove.add(i);
                } else {
                    ((DefaultTableModel) this.jThreads.getModel()).setValueAt(thread.getState(), i, 2);
                }
            }
        }
        if (!threadFound) {
            ((DefaultTableModel) this.jThreads.getModel()).addRow(new Object[]{thread.getId(), thread.getName(), thread.getState().toString()});
        } else {
            for (Integer row : rowsToRemove) {
                ((DefaultTableModel) this.jThreads.getModel()).removeRow(row);
            }
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel jButtonPanel;
    private javax.swing.JButton jConnect;
    private javax.swing.JTextArea jConsole;
    private javax.swing.JButton jDisconnect;
    private javax.swing.JTable jMessages;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JButton jSendMessage;
    private javax.swing.JSplitPane jSplitPane;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JTable jThreads;
    // End of variables declaration//GEN-END:variables
}
